package net.entelijan.cobean.notification;

import static org.junit.Assert.assertEquals;

import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;

import net.entelijan.cobean.core.ColumnDesc;
import net.entelijan.cobean.core.IMultiSelectionListCobean;
import net.entelijan.cobean.core.SelectionMode;
import net.entelijan.cobean.core.impl.INamedPropertyChangeListener;
import net.entelijan.cobean.core.impl.IPropertyChangeListenerAware;
import net.entelijan.cobean.table.DefaultTableInitializer;
import net.entelijan.cobean.util.CobeanUtil;
import net.entelijan.testutil.CobeanTestUtil;
import net.entelijan.testutil.SimpleBean;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.fest.swing.fixture.FrameFixture;
import org.fest.swing.fixture.JTableFixture;
import org.junit.Test;

public class MultiSelectionTableNotificationFestTestCase {

	private static Log log = LogFactory
			.getLog(MultiSelectionTableNotificationFestTestCase.class);

	public void dummy() {
		// Created to let testcases succeed even if all tests are disabled
	}
	
    @Test
	public void test() {
		TableNotificationTestFrame frame = new TableNotificationTestFrame("TF");
		FrameFixture frameFix = new FrameFixture(frame);
		try {
			frameFix.show();
			JTableFixture tableFix = frameFix.table("table");

			final RecordingPropertyChangeListener listener = new RecordingPropertyChangeListener(
					"value");
			final RecordingPropertyChangeListener selListener = new RecordingPropertyChangeListener(
					"selectedValue");
			IMultiSelectionListCobean<SimpleBean> cobean = init(frame,
					listener, selListener);
			List<SimpleBean> value = CobeanTestUtil
					.createSimpleBeanList("Der Assistent der Zauberer");
			cobean.setValue(value);
			assertEquals(1, listener.getNotificationCount());
			assertEquals(0, selListener.getNotificationCount());
			assertEventContentBean(null, CobeanTestUtil
					.createSimpleBeanList("Der Assistent der Zauberer"),
					"value", listener.getEventContents().get(0));

			tableFix.selectCell(tableFix.cell("Zauberer"));
			pause();
			assertEquals(1, listener.getNotificationCount());
			assertEquals(1, selListener.getNotificationCount());
			assertEventContentBean(null,
					createList(new SimpleBean("Zauberer")), "selectedValue",
					selListener.getEventContents().get(0));

			tableFix.selectCell(tableFix.cell("der"));
			pause();
			assertEquals(1, listener.getNotificationCount());
			assertEquals(2, selListener.getNotificationCount());
			assertEventContentBean(createList(new SimpleBean("Zauberer")),
					createList(new SimpleBean("der")), "selectedValue",
					selListener.getEventContents().get(1));

			tableFix.selectCell(tableFix.cell("der"));
			pause();
			assertEquals(1, listener.getNotificationCount());
			assertEquals(2, selListener.getNotificationCount());
			assertEventContentBean(createList(new SimpleBean("Zauberer")),
					createList(new SimpleBean("der")), "selectedValue",
					selListener.getEventContents().get(1));

			cobean.setSelectedValue(createList(new SimpleBean("der")));
			pause();
			assertEquals("der", tableFix.selectionValue());
			assertEquals(1, listener.getNotificationCount());
			assertEquals(2, selListener.getNotificationCount());
			assertEventContentBean(createList(new SimpleBean("Zauberer")),
					createList(new SimpleBean("der")), "selectedValue",
					selListener.getEventContents().get(1));

			cobean.setSelectedValue(createList(new SimpleBean("Assistent")));
			pause();
			assertEquals("Assistent", tableFix.selectionValue());
			assertEquals(1, listener.getNotificationCount());
			assertEquals(3, selListener.getNotificationCount());
			assertEventContentBean(createList(new SimpleBean("der")),
					createList(new SimpleBean("Assistent")), "selectedValue",
					selListener.getEventContents().get(2));

			cobean.setSelectedValue(null);
			pause();
			assertEquals(null, tableFix.selectionValue());
			assertEquals(1, listener.getNotificationCount());
			assertEquals(4, selListener.getNotificationCount());
			assertEventContentBean(createList(new SimpleBean("Assistent")),
					null, "selectedValue", selListener.getEventContents()
							.get(3));

		} finally {
			frameFix.cleanUp();
		}

	}

	private List<SimpleBean> createList(SimpleBean... simpleBeans) {
		ArrayList<SimpleBean> re = new ArrayList<SimpleBean>();
		for (SimpleBean sb : simpleBeans) {
			re.add(sb);
		}
		return re;
	}

	private <T> void assertEventContentBean(Object oldValue, Object newValue,
			String propertyName, EventContentBean eventContentBean) {
		assertEquals(oldValue, eventContentBean.getOldValue());
		assertEquals(newValue, eventContentBean.getNewValue());
		assertEquals(propertyName, eventContentBean.getPropertyName());

	}

	private synchronized void pause() {
		try {
			this.wait(100);
		} catch (InterruptedException e) {
			// Can be ignored
		}
	}

	@SuppressWarnings("unused")
	private synchronized void pauseLong() {
		try {
			this.wait(3000);
		} catch (InterruptedException e) {
			// Can be ignored
		}
	}

	private IMultiSelectionListCobean<SimpleBean> init(
			TableNotificationTestFrame frame, INamedPropertyChangeListener... nb) {
		final DefaultTableInitializer<SimpleBean> ini = new DefaultTableInitializer<SimpleBean>();
		ini.setColumnDescs(ColumnDesc.createPropertyOnlyColumnDescs("strVal"));
		ini.setCoTable(frame.getTable());
		ini.setSelectionMode(SelectionMode.MULTIPLE_INTERVAL);
		IMultiSelectionListCobean<SimpleBean> cobean = ini.initialize();
		log.debug("Created cobean: " + cobean);
		if (cobean instanceof IPropertyChangeListenerAware) {
			log.debug(cobean + " is IPropertyChangeListenerAware");
			for (INamedPropertyChangeListener l : nb) {
				((IPropertyChangeListenerAware) cobean)
						.setPropertyChangeListener(l);
			}
		} else {
			log.debug(cobean + " is NOT IPropertyChangeListenerAware");
			for (PropertyChangeListener l : nb) {
				CobeanUtil.addPropertyChangeListenerUsingReflection(cobean, l);
			}
		}
		return cobean;
	}

}
